﻿Imports Telerik.Web.Mvc
Imports System.Runtime.CompilerServices
Imports Telerik.Web.Mvc.Infrastructure
Imports System.ComponentModel

Public Module AvisoCustomBindingExtensions

    <Extension()> _
    Public Function ApplyFiltering(data As IQueryable(Of Aviso), filterDescriptors As IList(Of IFilterDescriptor)) As IQueryable(Of Aviso)
        If filterDescriptors.Any() Then
            For Each filterDescriptor In filterDescriptors
                If TypeOf filterDescriptor Is CompositeFilterDescriptor Then
                    Dim compo = DirectCast(filterDescriptor, CompositeFilterDescriptor)
                    Select Case compo.LogicalOperator
                        Case FilterCompositionLogicalOperator.And
                            Return ApplyFiltering(data, compo.FilterDescriptors.ToList)
                        Case FilterCompositionLogicalOperator.Or
                            Throw New NotImplementedException("Composite OR filter not implemented")
                    End Select
                End If
                Dim fltDesc = DirectCast(filterDescriptor, FilterDescriptor)
                Dim fltVal = fltDesc.ConvertedValue.ToString

                Select Case fltDesc.Member
                    Case "Paciente.NombreCompleto"
                        data = data.Where(Function(aviso) _
                                              aviso.Paciente.Nombre.Contains(fltVal) OrElse _
                                              aviso.Paciente.Apellido1.Contains(fltVal) OrElse _
                                              aviso.Paciente.Apellido2.Contains(fltVal))
                    Case "Dirección.Completa"
                        data = data.Where(Function(aviso) _
                                              aviso.Dirección.Vía.Contains(fltVal) OrElse _
                                              aviso.Dirección.Población.Nombre.Contains(fltVal) OrElse _
                                              aviso.Dirección.CódigoPostal.Contains(fltVal))
                    Case "PediatraAsindo.NombreCompleto"
                        data = data.Where(Function(aviso) _
                                              aviso.PediatraAsindo.Nombre.Contains(fltVal) OrElse _
                                              aviso.PediatraAsindo.Apellido1.Contains(fltVal) OrElse _
                                              aviso.PediatraAsindo.Apellido2.Contains(fltVal))
                    Case "FechaHora"
                        Dim fecha = CDate(fltDesc.ConvertedValue)

                        If fecha.Hour = 0 AndAlso fecha.Minute = 0 Then
                            ' Asumimos que el filtro es de días y no de una hora concreta
                            Dim fechaMásUno = fecha.AddDays(1)
                            Select Case fltDesc.Operator
                                Case FilterOperator.IsGreaterThan
                                    data = data.Where(Function(aviso) aviso.FechaHora >= fechaMásUno)
                                Case FilterOperator.IsGreaterThanOrEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora >= fecha)
                                Case FilterOperator.IsLessThan
                                    data = data.Where(Function(aviso) aviso.FechaHora < fecha)
                                Case FilterOperator.IsLessThanOrEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora < fechaMásUno)
                                Case FilterOperator.IsEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora >= fecha AndAlso aviso.FechaHora < fechaMásUno)
                                Case FilterOperator.IsNotEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora < fecha OrElse aviso.FechaHora >= fechaMásUno)
                                Case Else
                                    Throw New Exception("Operador desconocido")
                            End Select
                        Else
                            Select Case fltDesc.Operator
                                Case FilterOperator.IsGreaterThan
                                    data = data.Where(Function(aviso) aviso.FechaHora > fecha)
                                Case FilterOperator.IsGreaterThanOrEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora >= fecha)
                                Case FilterOperator.IsLessThan
                                    data = data.Where(Function(aviso) aviso.FechaHora < fecha)
                                Case FilterOperator.IsLessThanOrEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora <= fecha)
                                Case FilterOperator.IsEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora = fecha)
                                Case FilterOperator.IsNotEqualTo
                                    data = data.Where(Function(aviso) aviso.FechaHora <> fecha)
                                Case Else
                                    Throw New Exception("Operador desconocido")
                            End Select
                        End If

                End Select
            Next
        End If
        Return data
    End Function

  '  <Extension()> _
  '  Public Function ApplyGrouping(data As IQueryable(Of Aviso), groupDescriptors As IList(Of GroupDescriptor)) As IEnumerable
  '      Dim selector As Func(Of IEnumerable(Of Aviso), IEnumerable(Of AggregateFunctionsGroup)) = Nothing
  '      For Each group In groupDescriptors.Reverse()
  '          If selector Is Nothing Then
  '              If group.Member = "Customer.ContactName" Then
  '                  selector = Function(orders) BuildInnerGroup(orders, Function(o) o.Customer.ContactName)
  '              ElseIf group.Member = "OrderID" Then
  '                  selector = Function(orders) BuildInnerGroup(orders, Function(o) o.OrderID)
  '              ElseIf group.Member = "ShipAddress" Then
  '                  selector = Function(orders) BuildInnerGroup(orders, Function(o) o.ShipAddress)
  '              ElseIf group.Member = "OrderDate" Then
  '                  selector = Function(orders) BuildInnerGroup(orders, Function(o) o.OrderDate)
  '              End If
  '          Else
  '              If group.Member = "Customer.ContactName" Then
  '                  selector = BuildGroup(Function(o) o.Customer.ContactName, selector)
  '              ElseIf group.Member = "OrderID" Then
  '                  selector = BuildGroup(Function(o) o.OrderID, selector)
  '              ElseIf group.Member = "ShipAddress" Then
  '                  selector = BuildGroup(Function(o) o.ShipAddress, selector)
  '              ElseIf group.Member = "OrderDate" Then
  '                  selector = BuildGroup(Function(o) o.OrderDate, selector)
  '              End If
  '          End If
  '      Next
  '      Return selector.Invoke(data).ToList()
  '  End Function
  '  Private Function BuildGroup(Of T)(groupSelector As Func(Of Aviso, T), selectorBuilder As Func(Of IEnumerable(Of Aviso), IEnumerable(Of AggregateFunctionsGroup))) As Func(Of IEnumerable(Of Aviso), IEnumerable(Of AggregateFunctionsGroup))
  '      Dim tempSelector = selectorBuilder
		'Return Function(g) g.GroupBy(groupSelector).[Select](Function(c) New AggregateFunctionsGroup() With { _
		'	Key .Key = c.Key, _
		'	Key .HasSubgroups = True, _
		'	Key .Items = tempSelector.Invoke(c).ToList() _
		'})
  '  End Function
  '  Private Function BuildInnerGroup(Of T)(group As IEnumerable(Of Aviso), groupSelector As Func(Of Aviso, T)) As IEnumerable(Of AggregateFunctionsGroup)
		'Return group.GroupBy(groupSelector).[Select](Function(i) New AggregateFunctionsGroup() With { _
		'	Key .Key = i.Key, _
		'	Key .Items = i.ToList() _
		'})
  '  End Function
    <Extension()> _
    Public Function ApplyPaging(data As IQueryable(Of Aviso), currentPage As Integer, pageSize As Integer) As IQueryable(Of Aviso)
        If pageSize > 0 AndAlso currentPage > 0 Then
            data = data.Skip((currentPage - 1) * pageSize)
        End If
        data = data.Take(pageSize)
        Return data
    End Function
    <Extension()> _
    Public Function ApplySorting(data As IQueryable(Of Aviso), groupDescriptors As IList(Of GroupDescriptor), sortDescriptors As IList(Of SortDescriptor)) As IQueryable(Of Aviso)
        If groupDescriptors.Any() Then
            For Each groupDescriptor In groupDescriptors.Reverse()
                data = AddSortExpression(data, groupDescriptor.SortDirection, groupDescriptor.Member)
            Next
        End If
        If sortDescriptors.Any() Then
            For Each sortDescriptor As SortDescriptor In sortDescriptors
                data = AddSortExpression(data, sortDescriptor.SortDirection, sortDescriptor.Member)
            Next
        End If
        If Not groupDescriptors.Any AndAlso Not sortDescriptors.Any Then
            ' Ordenación por defecto. SIEMPRE tiene que haber una ordenación, la que sea, si queremos además paginación.
            data = data.OrderByDescending(Function(aviso) aviso.FechaHora)
        End If
        Return data
    End Function
    Private Function AddSortExpression(data As IQueryable(Of Aviso), sortDirection As ListSortDirection, memberName As String) As IQueryable(Of Aviso)
        If sortDirection = ListSortDirection.Ascending Then
            Select Case memberName
                Case "ID"
                    data = data.OrderBy(Function(aviso) aviso.id)
                Case "Fecha"
                    data = data.OrderBy(Function(aviso) aviso.FechaHora)
                Case "Paciente.NombreCompleto"
                    data = data.OrderBy(Function(aviso) aviso.Paciente.Apellido1).ThenBy(Function(aviso) aviso.Paciente.Apellido2).ThenBy(Function(aviso) aviso.Paciente.Nombre)
                Case "Dirección.Completa"
                    data = data.OrderBy(Function(aviso) aviso.Dirección.Vía)
                Case "PediatraAsindo.NombreCompleto"
                    data = data.OrderBy(Function(aviso) aviso.PediatraAsindo.Apellido1).ThenBy(Function(aviso) aviso.PediatraAsindo.Apellido2).ThenBy(Function(aviso) aviso.PediatraAsindo.Nombre)
            End Select
        Else
            Select Case memberName
                Case "ID"
                    data = data.OrderByDescending(Function(aviso) aviso.id)
                Case "Fecha"
                    data = data.OrderByDescending(Function(aviso) aviso.FechaHora)
                Case "Paciente.NombreCompleto"
                    data = data.OrderByDescending(Function(aviso) aviso.Paciente.Apellido1).ThenByDescending(Function(aviso) aviso.Paciente.Apellido2).ThenByDescending(Function(aviso) aviso.Paciente.Nombre)
                Case "Dirección.Completa"
                    data = data.OrderByDescending(Function(aviso) aviso.Dirección.Vía)
                Case "PediatraAsindo.NombreCompleto"
                    data = data.OrderByDescending(Function(aviso) aviso.PediatraAsindo.Apellido1).ThenByDescending(Function(aviso) aviso.PediatraAsindo.Apellido2).ThenByDescending(Function(aviso) aviso.PediatraAsindo.Nombre)
            End Select
        End If
        Return data
    End Function

End Module